package org.catdroid.bcnappsjam.barcelonaparticipa.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.accounts.NetworkErrorException;
import android.content.Context;

/**
 * La millor classe HttpUtil que he escrit fins a la data!
 * 
 * @author Roc Boronat
 * @date 20120412
 */
public class HttpUtils {

	public static final boolean GET = true;
	public static final boolean POST = false;

	public static final int TIMEOUT_LONG = 60000;
	public static final int TIMEOUT_SHORT = 30000;

	public static final String DOMAIN = "http://54.243.220.76:8080/NFCVOTE/";
	
	/** @return a DefaultHttpClient that timeouts after 10s/10s. */
	private static DefaultHttpClient getNewHttpClient() {

		// Parametres de Timeout:
		HttpParams httpParameters = new BasicHttpParams();
		// Set the timeout in milliseconds until a connection is established.
		HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_SHORT);
		// Set the default socket timeout (SO_TIMEOUT) in milliseconds which is
		// the timeout for waiting for data.
		HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SHORT);
		// Per les linies d'amunt, check
		// http://stackoverflow.com/questions/693997/how-to-set-httpresponse-timeout-for-android-in-java

		// Turn off stale checking. Our connections break all the time anyway,
		// and it's not worth it to pay the penalty of checking every time.
		HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);
		// @see:
		// http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/params/HttpConnectionParams.html#setStaleCheckingEnabled%28boolean%29
		return new DefaultHttpClient(httpParameters);
	}

	/** @return a DefaultHttpClient that timeouts after 60s/60s. */
	private static DefaultHttpClient getNewLongHttpClient() {

		// Parametres de Timeout:
		HttpParams httpParameters = new BasicHttpParams();
		// Set the timeout in milliseconds until a connection is established.
		HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_LONG);
		// Set the default socket timeout (SO_TIMEOUT) in milliseconds which is
		// the timeout for waiting for data.
		HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_LONG);
		// Per les linies d'amunt, check
		// http://stackoverflow.com/questions/693997/how-to-set-httpresponse-timeout-for-android-in-java

		// Turn off stale checking. Our connections break all the time anyway,
		// and it's not worth it to pay the penalty of checking every time.
		HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);
		// @see:
		// http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/params/HttpConnectionParams.html#setStaleCheckingEnabled%28boolean%29
		return new DefaultHttpClient(httpParameters);
	}

	/** M�tode per a cridar una ruta passant UN par�metre */
	public static String requestData(String context, String paramName, String paramValue, boolean method, Context c) throws Exception {
		Map<String, String> params = new HashMap<String, String>();
		params.put(paramName, paramValue);
		return requestData(context, params, method, c);
	}

	/** M�tode per a cridar una ruta passant un Map de par�metres */
	public static String requestData(String context, Map<String, String> params, boolean method, Context c) throws Exception {
		return requestData(context, params, method, false, c);
	}

	/** M�tode per a cridar una ruta passant un Map de par�metres */
	public static String requestData(String urlContext, Map<String, String> params, boolean method, boolean gzip, Context c) throws Exception {
		if (!Utils.isNetworkAvailable(c)) {
			throw new NetworkErrorException();
		}

		gzip = false; // A saco, per fer proves, anem evitant problemes

		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		
		if (params != null) {
			for (Entry<String, String> param : params.entrySet()) {
				nameValuePairs.add(new BasicNameValuePair(param.getKey(), param.getValue()));
			}
		}

		if (gzip) {
			nameValuePairs.add(new BasicNameValuePair("gzip", "true"));
		}

		try {
			HttpClient httpclient = getNewHttpClient();
			HttpResponse response = null;
			if (method == GET) {
				HttpGet httpget = new HttpGet(DOMAIN.concat(urlContext).concat("?").concat(URLEncodedUtils.format(nameValuePairs, "UTF-8")));
				response = httpclient.execute(httpget);
			} else {
				HttpPost httppost = new HttpPost(DOMAIN.concat(urlContext));
				httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
				response = httpclient.execute(httppost);
			}
			return convertStreamToString(response.getEntity().getContent(), gzip);
		} catch (Exception e) {
			throw e;
		}
	}

	private static String convertStreamToString(InputStream is, boolean gzip) throws IOException {
		BufferedReader reader = null;

		if (gzip) {
			try {
				reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(is)));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			reader = new BufferedReader(new InputStreamReader(is));
		}

		StringBuilder sb = new StringBuilder();

		String line = null;
		try {
			if (reader != null) {
				while ((line = reader.readLine()) != null) {
					sb.append((line.concat("\n")));
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString().trim();
	}
}